package com.example.strategy;

import com.example.entity.DayHourChargeConfig;
import com.example.entity.ParkingRecord;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.Comparator;
import java.util.Optional;
import java.util.function.Function;

@FunctionalInterface
public interface ParkingFeeStrategy {
    BigDecimal calculateFee(ParkingRecord record, DayHourChargeConfig config);

    // 基础策略 - 按小时计费
    static ParkingFeeStrategy hourlyStrategy() {
        return (record, config) -> {
            long minutes = Duration.between(record.getEntryTime(), record.getExitTime()).toMinutes();
            double hours = Math.ceil(minutes / 60.0);

            return Optional.ofNullable(config.getHourlyRates())
                    .map(rates -> rates.stream()
                            .filter(rate -> rate.getHours() <= hours)
                            .max((r1, r2) -> r1.getHours() - r2.getHours())
                            .map(rate -> rate.getRate())
                            .orElse(BigDecimal.ZERO)).get()
                            .multiply(BigDecimal.valueOf(hours));

        };
//        return (record, config) -> calculateHours(record)
//                .flatMap(hours -> findApplicableRate(config, hours))
//                .orElse(BigDecimal.ZERO);
    }

//    private static Optional<BigDecimal> calculateHours(ParkingRecord record) {
//        return Optional.ofNullable(record)
//                .map(r -> Duration.between(r.getEntryTime(), r.getExitTime()).toMinutes())
//                .map(minutes -> Math.ceil(minutes / 60.0));
//    }
//
//    private static Optional<BigDecimal> findApplicableRate(DayHourChargeConfig config, double hours) {
//        return Optional.ofNullable(config.getHourlyRates())
//                .flatMap(rates -> rates.stream()
//                        .filter(rate -> rate.getHours() <= hours)
//                        .max(Comparator.comparingInt(DayHourChargeConfig.HourlyRate::getHours))
//                        .map(rate -> rate.getRate().multiply(BigDecimal.valueOf(hours)));
//    }

    // 策略 - 半小时计费
    static ParkingFeeStrategy halfHourStrategy() {
        return (record, config) -> {
            long minutes = Duration.between(record.getEntryTime(), record.getExitTime()).toMinutes();
            long halfHours = (long) Math.ceil(minutes / 30.0);
            return config.getHalfHourRate().multiply(BigDecimal.valueOf(halfHours));
        };
    }

    // 策略组合器
    default ParkingFeeStrategy andThen(Function<BigDecimal, BigDecimal> after) {
        return (record, config) -> after.apply(this.calculateFee(record, config));
    }

    // 免费时间策略
    static Function<BigDecimal, BigDecimal> freeTimeStrategy(ParkingRecord record, DayHourChargeConfig config) {
        return fee -> {
            long minutes = Duration.between(record.getEntryTime(), record.getExitTime()).toMinutes();
            return minutes <= config.getFreeTime() ? BigDecimal.ZERO : fee;
        };
    }

    // 封顶费用策略
    static Function<BigDecimal, BigDecimal> maxFeeStrategy(DayHourChargeConfig config) {
        return fee -> config.getChargeMaxAmount() != null ?
                fee.min(config.getChargeMaxAmount()) : fee;
    }

    // 过夜费策略
    static Function<BigDecimal, BigDecimal> overnightFeeStrategy(ParkingRecord record, DayHourChargeConfig config) {
        return fee -> {
            int nights = calculateOvernightCount(record, config);
            return fee.add(config.getOverNightCharges().multiply(BigDecimal.valueOf(nights)));
        };
    }

    private static int calculateOvernightCount(ParkingRecord record, DayHourChargeConfig config) {
        // 实现过夜次数计算逻辑
        return 0;
    }
}
